#!/bin/env bash

function bm() {

    local index_width=3

    local bm_file="${HOME}/.bash_bookmarks"
    local bm_file_tmp="${HOME}/.bash_bookmarks.tmp"

    if [[ $1 =~ ^[0-9]+$ ]]; then

        if [[ ! -f "${bm_file}" ]]; then
            echo "Bookmarks' file (${bm_file}) doesn't exist"
            return 1
        elif [[ ! -s "${bm_file}" ]]; then
            echo "There are no bookmarks to run"
            return 1
        else
            local cmd=$(grep -E "^\s*$1:\s" "${bm_file}" | cut -d ':' -f 2- | xargs)
            if [[ -n "$cmd" ]]; then
                echo "${cmd}"
                echo "=========="
                eval "${cmd}"
                return 0
            else
                echo "Bookmark not found"
                return 1
            fi
        fi

    else

        local action=$1

        case "${action}" in
            "add" | "a")
                shift
                local command_to_bm="$@"
                if [[ ! -n "${command_to_bm}" ]]; then
                    echo "You didn't specify which command to save as a bookmark"
                    return 1
                elif [[ ! -f "${bm_file}" ]]; then
                    touch "${bm_file}"
                    echo "Bookmarks' file (${bm_file}) didn't exist, created it"
                fi
                local bm_lines_count=$(wc -l "${bm_file}" | cut -d" " -f1)
                printf "%${index_width}d: %s\n" $((bm_lines_count + 1)) "${command_to_bm}" >> "${bm_file}" 
                echo "Command \`${command_to_bm}\` saved to bookmarks with index $((bm_lines_count + 1))"
                return 0
                ;;
            
            "remove" | "rm" | "delete" | "del" | "d")
                if [[ ! -f "${bm_file}" ]]; then
                    echo "Bookmarks' file (${bm_file}) doesn't exist"
                    return 1
                elif [[ ! -s "${bm_file}" ]]; then
                    echo "There are no bookmarks to delete"
                    return 1
                else
                    shift
                    for line_to_delete in "$@"; do
                        if grep -q -E "^\s*${line_to_delete}:\s" "${bm_file}"; then
                            sed -i "/^\s*${line_to_delete}:\s/d" "${bm_file}"
                            echo "Bookmark with index ${line_to_delete} removed"
                        else
                            echo "There is no bookmark with index ${line_to_delete}"
                        fi
                    done
                    return 0
                fi
                ;;

            "reindex" | "re")
                if [[ ! -f "${bm_file}" ]]; then
                    echo "Bookmarks' file (${bm_file}) doesn't exist"
                    return 1
                elif [[ ! -s "${bm_file}" ]]; then
                    echo "No bookmarks to reindex"
                    return 1
                else
                    local i=1
                    while IFS= read -r bm_line; do
                        local cmd=$(echo "${bm_line}" | sed -E 's/^\s*[0-9]+:\s+//')
                        printf "%${index_width}d: %s\n" "${i}" "${cmd}" >> "${bm_file_tmp}" 
                        i=$((i + 1))
                    done < "${bm_file}"
                    mv "${bm_file_tmp}" "${bm_file}"
                    echo "Bookmarks reindexed"
                    return 0
                fi
                ;;

            "ls" | "list" | "l")
                if [[ ! -f "${bm_file}" ]]; then
                    echo "Bookmarks' file (${bm_file}) doesn't exist"
                    return 1
                fi
                echo "${bm_file}"
                echo "=========="
                if [[ ! -s "${bm_file}" ]]; then
                    echo "No bookmarks to show"
                else
                    cat "${bm_file}"
                fi
                return 0
                ;;

            "run" | "r")
                shift
                bm "$@"
                ;;

            "clear" | "cl")
                if [[ ! -f "${bm_file}" ]]; then
                    echo "Bookmarks' file (${bm_file}) didn't exist, created it"
                    return 0
                fi
                truncate -s 0 "${bm_file}"
                echo "Bookmarks' file (${bm_file}) is now empty"
                return 0
                ;;

            "edit" | "ed" | "e")
                if [[ ! -f "${bm_file}" ]]; then
                    echo "Bookmarks' file (${bm_file}) didn't exist, created it"
                fi
                if [[ -n "${EDITOR}" ]]; then
                    "${EDITOR}" "${bm_file}"
                else
                    $(( command -v vim )) "${bm_file}"
                fi
                return 0
                ;;

            *)
                echo "Save bash commands as bookmarks into the file (~/.bash_bookmarks) and call them by index"
                echo "Usage:"
                echo "  bm list|ls|l                     - list saved bookmarks"
                echo "  bm run|r INDEX                   - run command by its INDEX"
                echo "  bm INDEX                         - same as above"
                echo "  bm add|a COMMAND                 - add COMMAND to bookmarks; use quotes around COMMAND to escape special characters"
                echo "  bm edit|ed|e                     - open bookmarks' file in editor"
                echo "  bm remove|rm|delete|del|d INDEX  - remove command from bookmarks by INDEX"
                echo "  bm reindex|re                    - reindex bookmarks"
                echo "  bm clear|cl                      - delete all bookmarks"
                return 0
                ;;
        esac
    fi
}

bm "$@"
